package top.chukongxiang.project.base.utils;

import org.springframework.beans.BeanUtils;

import java.io.*;
import java.lang.reflect.Array;
import java.util.*;
import java.util.function.*;
import java.util.stream.Collectors;

@SuppressWarnings("unchecked")
public class ArrayUtils<T> {


    /**
     * 数组转list
     * @param ts 目标数组
     * @return
     */
    public static <T> List<T> toList(T[]ts){
        if (ts==null) {
            return null;
        }
        return new ArrayList<>(Arrays.asList(ts));
    }

    /**
     * 深层拷贝list
     * @param list
     * @param <T>
     * @return
     */
    public static <T> List<T> deepCopy(List<T> list){
        List<T> dest = null;
        ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
        ObjectOutputStream out = null;
        try {
            out = new ObjectOutputStream(byteOut);
            out.writeObject(list);

            ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
            ObjectInputStream in = new ObjectInputStream(byteIn);
            dest = (List<T>) in.readObject();
            in.close();
            byteIn.close();
        } catch (Exception e) {
            e.printStackTrace();
        }  finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (byteOut != null ) {
                    byteOut.close();
                }
            } catch (IOException e) {
                out = null;
                byteOut = null;
                e.printStackTrace();
            }
        }
        return dest;
    }

    /**
     * 深拷贝数组
     * @param sources
     * @param <T>
     * @return
     */
    public static <T> T[] deepCopy(T[] sources){
        if (sources==null) {
            return null;
        }
        return deepCopy(sources,sources.length);
    }

    /**
     * 深拷贝指定长度数组
     * @param sources
     * @param length
     * @param <T>
     * @return
     */
    public static <T> T[] deepCopy(T[] sources,int length){
        if (length<0) {
            throw new RuntimeException("com.dfyj.common.utils.ArrayUtils.deepCopy(T[] sources, int length) length is "+length);
        }
        if (sources==null) {
            return null;
        }
        T[] dst = (T[]) Array.newInstance(sources[0].getClass(),length);
        for (int i=0;i<dst.length;i++){ dst[i] = sources[i]; }
        return dst;
    }

    /**
     * forEach循环迭代器
     * @param startIndex 起始index
     * @param elements 迭代器
     * @param action 回调（index，elment）
     * @param <T>
     */
    public static <T> void forEach(int startIndex,Iterable<? extends T> elements, BiConsumer<Integer, ? super T> action) {
        Objects.requireNonNull(elements);
        Objects.requireNonNull(action);
        if(startIndex < 0) {
            startIndex = 0;
        }
        int index = 0;
        for (T element : elements) {
            index++;
            if(index <= startIndex) {
                continue;
            }
            action.accept(index-1, element);
        }
    }

    /**
     * 将String数组转化为Integer数组，不能转换的为null
     * @param strs
     * @return
     */
    public static Integer[] parseIntegerArray(String[] strs){
        Integer[] ints = new Integer[strs.length];
        for(int i=0;i<strs.length;i++){
            try {
                if(strs[i]==null) throw new RuntimeException("不能转换");
                ints[i] = Integer.parseInt(strs[i]);
            } catch (Exception e) {
                e.printStackTrace();
                ints[i] = null;
            }
        }
        return ints;
    }

//    public static void main(String[] args) {
//        Date[] integers = parseArray(new String[]{"2020年01月01日","2.3"}, Date.class);
//        Arrays.stream(integers).forEach(integer -> {
//            System.out.println(integer);
//        });
//
//    }

    /**
     * 字符串数组转换为目标类数组
     * @param strings 字符串数组
     * @param clazz 目标类型(仅支持String,Integer,Boolean,Float,Double,Date)
     * @param <T>
     * @return
     */
    public static <T> T[] parseArray(String[] strings,Class<? extends  T> clazz){
            T[] ts = (T[])Array.newInstance(clazz, strings.length);
            for(int i=0;i<strings.length;i++){
                try {
                    switch (clazz.getName()){
                        case "java.lang.String":{ ts[i] = (T)strings[i];break; }
                        case "java.lang.Integer":{ ts[i] = (T)(Integer)Integer.parseInt(strings[i]);break; }
                        case "java.lang.Boolean":{ ts[i] = (T)(Boolean)Boolean.parseBoolean(strings[i]);break; }
                        case "java.lang.Float":{ ts[i] = (T)(Float)Float.parseFloat(strings[i]);break; }
                        case "java.lang.Double":{ ts[i] = (T)(Double)Double.parseDouble(strings[i]);break; }
                        case "java.util.Date" :{ts[i] = (T) DateUtils.parseDate(strings[i]);break; }
                        default: {
                            throw new RuntimeException("不支持的数据类型：" + clazz.getName());
                        }
                    }
                } catch (Exception e) {
                    System.err.println("不能将"+strings[i]+"转换为"+clazz.getName()+"类型");
                    continue;
                }
            }
            return ts;
    }

    /**
     * list转数组
     * @param list
     * @param <T>
     * @return
     */
    public static <T> T[] toArray(Collection<T> list,Class<T> clazz){
        if (list==null) {
            return null;
        }
        else if (list.size() == 0) {
            if (clazz == null) {
                return null;
            }
            return (T[])Array.newInstance(clazz,0);
        }
        Class<?> tClass = null;
        Iterator<T> iterator = list.iterator();
        while (iterator.hasNext()){
            T t = iterator.next();
            tClass = t.getClass();
            break;
        }
        T[] ts = (T[]) Array.newInstance(tClass, list.size());
        iterator = list.iterator();
        int i = 0;
        while (iterator.hasNext()) {
            T t = iterator.next();
            ts[i] = t;
            i++;
        }
        return ts;
    }

    /**
     * 分隔符分割字符串
     * @param strs
     * @param spara
     * @return
     */
    public static String[] toArray(String strs,String spara){
        if (strs==null) {
            return null;
        }
        return strs.split(spara);
    }

    /**
     * 剪切list
     * @param list 源list
     * @param start 开始位置
     * @param len 结束位置
     * @param <T>
     * @return
     */
    public static <T> List<T> cut(List<T> list, int start, int len) {
        List<T> rs = new ArrayList<>();
        if (start > (list.size() - 1)) { return rs; }
        for (int i = start; i < list.size() && i < start + len; i++) {
            rs.add(list.get(i));
        }
        return rs;
    }

    /**
     * 字符串逗号分割
     * @param strs
     * @return
     */
    public static String[] toArray(String strs){
        return toArray(strs,",");
    }

    /**
     * 数组转字符串
     * @param arr
     * @return
     */
    public static String arrToString(String[] arr){
        return arrToString(arr,",");
    }
    public static String arrToString(String[] arr,String spara){
        if(arr==null) {
            return null;
        }
        StringBuilder sb = new StringBuilder();
        for(String s:arr){
            if(s==null) {
                continue;
            }
            sb.append(s);
            sb.append(spara);
        }
        if(sb.toString().endsWith(spara)){
            sb.setLength(sb.length()-1);
        }
        return sb.toString();
    }

    /**
     * list转字符串
     * @param list
     * @return
     */
    public static <T> String listToString(List<T> list){
        return listToString(list,",");
    }
    public static <T> String listToString(List<T> list,String spara){
        StringBuilder sb = new StringBuilder();
        for(Object o:list){
            sb.append(o.toString());
            sb.append(spara);
        }
        if(sb.toString().endsWith(spara)){
            sb.setLength(sb.length()-1);
        }
        return sb.toString();
    }

    /**
     * collection转为list
     * @param sets
     * @param <T>
     * @return
     */
    public  static <T> List<T> toList(Collection<T> sets){
        if (sets instanceof List) {
            return (List<T>)sets;
        }
        return new ArrayList<>(sets);
    }

    /**
     * 集合是否为空或null
     * @param collection
     * @param <T>
     * @return
     */
    public static <T> boolean isEmpty(Collection<T> collection){
        if (collection==null) {
            return true;
        }
        return collection.isEmpty();
    }

    /**
     * 对象序列化为byte数组
     * @param obj
     * @param <T>
     * @return
     */
    public static<T> Optional<byte[]> objectToBytes(T obj){
        byte[] bytes = null;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ObjectOutputStream sOut;
        try {
            sOut = new ObjectOutputStream(out);
            sOut.writeObject(obj);
            sOut.flush();
            bytes= out.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return Optional.ofNullable(bytes);
    }

    /**
     * byte数组序列化为对象
     * @param bytes
     * @param <T>
     * @return
     */
    public static<T> Optional<T> bytesToObject(byte[] bytes) {
        T t = null;
        ByteArrayInputStream in = new ByteArrayInputStream(bytes);
        ObjectInputStream sIn;
        try {
            sIn = new ObjectInputStream(in);
            t = (T)sIn.readObject();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return Optional.ofNullable(t);
    }

    /**
     * 集合内容是否相等
     * equals比较
     * @param src
     * @param dst
     * @param <T>
     * @return
     */
    public static <T> boolean equals(Collection<T> src, Collection<T> dst) {
        if (src==dst) {
            return true;
        }
        if (src == null || dst == null) {
            return false;
        }
        if (src.size()!=dst.size()) {
            return false;
        }
        Object[] srcObjects = src.toArray();
        Object[] dstObjects = dst.toArray();
        for (int i=0;i<src.size();i++){
            if (! srcObjects[i].equals(dstObjects[i])) {
                return false;
            }
        }
        return true;
    }

    /**
     * 遍历数组，循环调用 BiPredicate（t,r），返回true时返回true
     * @param ts
     * @param r
     * @param compare
     * @param <T>
     * @param <R>
     * @return
     */
    public static <T,R> boolean contains(T[] ts, R r, BiPredicate<T,R> compare){
        for (T t1 : ts) {
            boolean has = compare.test(t1, r);
            if (has) {
                return true;
            }
        }
        return false;
    }
    public static <T,R> boolean contains(List<T> ts, R r, BiPredicate<T,R> compare){
        for (T t1 : ts) {
            boolean has = compare.test(t1, r);
            if (has) {
                return true;
            }
        }
        return false;
    }

    /**
     * 满足条件的会被连接
     */
    public static <T> List<T> concat(List<T> src, List<? extends T> dst, Function<T, Boolean> predicate){
        List<T> rs = new ArrayList<>(src);
        dst.forEach(d->{
            Boolean can = predicate.apply(d);
            if (can!=null && can) {
                rs.add(d);
            }
        });
        return rs;
    }

    //满足条件的会被连接
    public static <T> T[] concat(Class<T> clazz, T[] ...src){
        if (src.length==0) { return null; }
        else if (src.length==1) { return src[1]; }
        List<T> list = new ArrayList<>();
        for (T[] ts : src) {
            list.addAll(toList(ts));
        }
        return toArray(list, clazz);
    }

    /********* jdk8 filter封装 *******/
    public static <T> List<T> filter(Collection<T> list, Predicate<? super T> predicate) {
        return list.stream().filter(predicate).collect(Collectors.toList());
    }
    public static <T> T[] filter(T[] ts, Class<T> clazz, Predicate<? super T> predicate) {
        List<T> tempList = new ArrayList<>();
        for (T t : ts) {
            if (predicate.test(t)) {
                tempList.add(t);
            }
        }
        return toArray(tempList, clazz);
    }

    /********* jdk8 count封装 *******/
    public static <T> int count(List<T> list, Predicate<? super T> predicate) {
        return (int) list.stream().filter(predicate).count();
    }

    /**
     * 满足条件的，会被添加进集合
     * @param list
     * @param dst
     * @param compare
     * @param <T>
     */
    public static <T> void add(List<T> list, T dst, BiPredicate<T,T> compare){
        List<T> temp = new ArrayList<>(list);
        temp.forEach(t -> {
            if (compare.test(t, dst)) {
                list.add(t);
            }
        });
    }

    /********* jdk8 map封装 *******/
    public static <T,R> List<R> map(Collection<T> list, Function<T, R> function){
        return list.stream().map(function).collect(Collectors.toList());
    }
    public static <T,R> List<R> map(T[] list, Function<T, R> function){
        return map(toList(list), function);
    }
    public static <T,R> Set<R> mapSet(Collection<T> list, Function<T, R> function){
        return list.stream().map(function).collect(Collectors.toSet());
    }

    public static <T,R> List<R> mapDistinct(List<T> list, Function<T, R> function){
        return list.stream().map(function).distinct().collect(Collectors.toList());
    }
    public static <T,R,E> Map<R,E> toMap (Collection<T> list, Function<T,R> key, Function<T, E> value){
        return toMap(list, key, value, new HashMap<>());
    }
    public static <T,R,E> Map<R,E> toMap (Collection<T> list, Function<T,R> key, Function<T, E> value, Map<R,E> defaultValue){
        if (list==null) {
            return defaultValue;
        }
        return list.stream().collect(Collectors.toMap(key, value));
    }

    public static <T> void forEach(T[] ts, Consumer<T> compare ){
        for (T t : ts) {
            compare.accept(t);
        }
    }
    public static <T> void forEach(Collection<T> ts, Consumer<T> compare ){
        for (T t : ts) {
            compare.accept(t);
        }
    }
    public static <T,R> void setNull(Collection<T> ts, BiFunction<T, R, T> ... setMethods) {
        for (T t : ts) {
            for (BiFunction<T, R, T> setMethod : setMethods) {
                setMethod.apply(t, null);
            }
        }
    }

    public static <T,R> void setNull(Collection<T> ts, BiConsumer<T, R> ... setMethods) {
        for (T t : ts) {
            for (BiConsumer<T, R> setMethod : setMethods) {
                setMethod.accept(t, null);
            }
        }
    }

    public static <T> void replace(List<T> ts, Predicate<? super T> predicate, T t){
        List<Integer> indies = rep(ts, predicate);
        indies.forEach(i-> ts.add(i, t));
    }

    private static <T> List<Integer> rep(List<T> ts, Predicate<? super T> predicate) {
        Iterator<T> iterator = ts.iterator();
        List<Integer> indies = new ArrayList<>();
        int index = 0;
        while (iterator.hasNext()) {
            T next = iterator.next();
            if (predicate.test(next)) {
                indies.add(index);
                iterator.remove();
            }
            index++;
        }
        ts.removeIf(Objects::isNull);
        return indies;
    }

    public static <T> void replace(List<T> ts, Predicate<? super T> predicate, Function<List<T>, T> function){
        List<Integer> indies = rep(ts, predicate);
        indies.forEach(i-> ts.add(i, function.apply(ts)));
    }

    public static <T, R> Map<R,List<T>> groupBy(List<T> ts, Function<? super T, ? extends R> classifier) {
        return ts.stream().collect(Collectors.groupingBy(classifier));
    }

    public static <T> T getOne(List<T> list, Predicate<T> predicate){
        for (T t : list) {
            if (predicate.test(t)) {
                return t;
            }
        }
        return null;
    }

    public static <T,E> List<E> convert(Collection<T> collection, Class<E> clazz, BiConsumer<T,E> consumer) {
        Iterator<T> iterator = collection.iterator();
        return collection.stream().map(item -> {
            T next = iterator.next();
            E instance;
            try {
                instance = clazz.newInstance();
            } catch (InstantiationException | IllegalAccessException e) {
                e.printStackTrace();
                return null;
            }
            BeanUtils.copyProperties(next, instance);
            if (consumer!=null) {
                consumer.accept(next, instance);
            }
            return instance;
        }).collect(Collectors.toList());
    }
    public static <T,E> List<E> convert(Collection<T> collection, Class<E> clazz) {
        return convert(collection, clazz, null);
    }

    public static <T> Set<T> asSet(T[] ts) {
        return ts == null ? new HashSet<>() : new HashSet<>(Arrays.asList(ts));
    }

    public static <T, R> List<Function<T, R>> asFunction(Function<T, R> function) {
        List<Function<T,R>> list = new ArrayList<>();
        list.add(function);
        return list;
    }

    public static class MyList<T> extends ArrayList<T> {
        public MyList<T> chainAdd(T... ts) {
            this.addAll(Arrays.asList(ts));
            return this;
        }

        public MyList<T> chainAddAll(T[] ts) {
            this.addAll(Arrays.asList(ts));
            return this;
        }

        public MyList<T> chainAddAll(List<T> ts) {
            this.addAll(ts);
            return this;
        }
    }
}
